package org.study.minio.boot.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.study.minio.boot.config.MinioConstant;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 作用描述
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2023年12月13日
 */
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/baidu")
public class BaiduController {
    private static final String UPLOAD_DIR = MinioConstant.DESKTOP + File.separator + "uploads" + File.separator;
    private static final String DOWNLOAD_DIR = MinioConstant.DESKTOP + File.separator + "uploads" + File.separator;// downloads
    private static final String FILE_INFO_DIR = MinioConstant.DESKTOP + File.separator + "file_info" + File.separator;

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return new ResponseEntity<>("请选择一个文件上传", HttpStatus.OK);
        }
        try {
            byte[] bytes = file.getBytes();
            Path path = Paths.get(UPLOAD_DIR + file.getOriginalFilename());
            Files.write(path, bytes);
            return new ResponseEntity<>("文件上传成功", HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseEntity<>("文件上传失败", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @GetMapping("/download/{filename:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String filename) throws MalformedURLException {
        Path path = Paths.get(DOWNLOAD_DIR + filename);
        Resource resource1 = new UrlResource(path.toUri());
        Resource resource = new UrlResource("http://127.0.0.1:19000/bucket-test/test.mp4");
        return ResponseEntity.ok()
                .header("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }

    /**
     * "大文件秒传"是指在文件上传时，如果服务器已经存在与要上传的文件完全相同的文件，则可以直接使用已有的文件，而无需重新上传。这可以大大节省上传时间和网络带宽。
     * 在Spring Boot中实现大文件秒传，可以通过以下步骤实现：
     * 1、计算文件的哈希值：在上传文件之前，先计算文件的哈希值。哈希值是一个唯一的字符串，可以用来标识文件。可以使用MD5或SHA-256等算法计算哈希值。
     * 2、检查服务器是否已有相同哈希值的文件：在上传文件之前，向服务器发送一个请求，询问是否已经存在相同哈希值的文件。如果已经存在，则可以直接使用已有的文件，无需重新上传。
     * 3、实现文件上传和下载接口：如果服务器没有相同哈希值的文件，则需要实现文件上传和下载接口。可以使用Spring Boot提供的MultipartFile接口来处理文件上传，使用ResponseEntity接口来处理文件下载。
     */
    @PostMapping("/upload/big")
    public ResponseEntity<String> uploadBigFile(@RequestParam("file") MultipartFile file) throws NoSuchAlgorithmException, IOException {
        String fileName = file.getOriginalFilename();
        String fileMd5 = getFileMd5(file);
        Path fileInfoPath = Paths.get(FILE_INFO_DIR + fileMd5);
        if (Files.exists(fileInfoPath)) {
            return new ResponseEntity<>("文件已存在，无需上传", HttpStatus.OK);
        }
        byte[] bytes = file.getBytes();
        Path path = Paths.get(UPLOAD_DIR + fileName);
        Files.write(path, bytes);
        Files.write(fileInfoPath, fileName.getBytes());
        return new ResponseEntity<>("文件上传成功", HttpStatus.OK);
    }

    @GetMapping("/download/big/{fileMd5}")
    public ResponseEntity<Object> downloadBigFile(@PathVariable String fileMd5) throws IOException {
        Path fileInfoPath = Paths.get(FILE_INFO_DIR + fileMd5);
        if (!Files.exists(fileInfoPath)) {
            return new ResponseEntity<>("文件不存在", HttpStatus.NOT_FOUND);
        }
        String fileName = new String(Files.readAllBytes(fileInfoPath));
        Path path = Paths.get(UPLOAD_DIR + fileName);
        Resource resource = new UrlResource(path.toUri());
        return ResponseEntity.ok()
                .header("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }

    private String getFileMd5(MultipartFile file) throws NoSuchAlgorithmException, IOException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] fileBytes = file.getBytes();
        md.update(fileBytes);
        byte[] digest = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            String hex = Integer.toHexString(b & 0xff);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}
